#include <Rectangle.h>
#include <cmath>


    struct RectangleState
{
    virtual
    ~RectangleState()
    {
    }

    virtual double
    getArea(const RectangleLength&, const RectangleWidth&) const=0;

    virtual double
    getPerimeter(const RectangleLength&, const RectangleWidth&) const=0;

    virtual bool
    isValid() const = 0;

};

struct ValidRectangleState : public RectangleState
{
    virtual double
    getArea(const RectangleLength&, const RectangleWidth&) const;

    virtual double
    getPerimeter(const RectangleLength&, const RectangleWidth&) const;

    virtual bool
    isValid() const;
};

struct InvalidRectangleState : public RectangleState
{
    virtual double
    getArea(const RectangleLength&, const RectangleWidth&) const;

    virtual double
    getPerimeter(const RectangleLength&, const RectangleWidth&) const;

    virtual bool
    isValid() const;
};

double
ValidRectangleState::getArea(const RectangleLength& length,
        const RectangleWidth& width) const
{
    return length * width;
}

double
ValidRectangleState::getPerimeter(const RectangleLength& length,
        const RectangleWidth& width) const
{
    return 2 * (length + width);
}

bool
ValidRectangleState::isValid() const
{
    return true;
}

double
InvalidRectangleState::getArea(const RectangleLength& length,
        const RectangleWidth& width) const
{
    return 0;
}

double
InvalidRectangleState::getPerimeter(const RectangleLength& length,
        const RectangleWidth& width) const
{
    return 0;
}

bool
InvalidRectangleState::isValid() const
{
    return false;
}

RectangleState *
getRectangleState(const RectangleLength& length, const RectangleWidth& width)
{
    static ValidRectangleState validRectangleState;
    static InvalidRectangleState invalidRectangleState;

    LengthRange lengthRange;
    WidthRange widthRange;
    return (lengthRange(length) && widthRange(width)) ? ((RectangleState *) &validRectangleState)
            : ((RectangleState *) &invalidRectangleState);
}


Rectangle::Rectangle(double length, double width) :
    length_m(length),
    width_m(width)
{
    updateValidState();
}

double
Rectangle::getArea() const
{
    return state_m->getArea(length_m, width_m);

}

double
Rectangle::getPerimeter() const
{
    return state_m->getPerimeter(length_m, width_m);
}

bool
Rectangle::isValid() const
{
    return state_m->isValid();
}

bool
Rectangle::changeLength(double length)
{
    bool isDone = false;
    LengthRange range;
    if(isDone=(range)(RectangleLength(length)))
    {
        length_m=RectangleLength(length);
    }
    updateValidState();
    return isDone;
}

bool
Rectangle::changeWidth(double width)
{
    bool isDone = false;
    WidthRange range;
    if(isDone=range(RectangleWidth(width)))
    {
        width_m=RectangleWidth(width);
    }
    updateValidState();
    return isDone;
}

void
Rectangle::updateValidState()
{
    state_m = getRectangleState(length_m, width_m);
}

